﻿using Unity.Mathematics;
using UnityEngine;

namespace Yoozoo.Gameplay.RTS
{
    public class SpriteSheetAnimation16Directions
    {
        // 八个方向对应的枚举值和对应的动画编号
        // 其中左侧3个方向需要翻转，动画编号和右侧相同
        //RIGHT_DOWN = 0,                       => 0
        //DOWN = 1,                             => 1
        //LEFT_DOWN = 2,                        => 0
        //LEFT = 3,                             => 4
        //LEFT_UP = 4,                          => 3
        //UP = 5,                               => 2
        //RIGHT_UP = 6,                         => 3
        //RIGHT = 7                             => 4

        // 新增8个方向，用于汽车的转向
        // 命名： XXX_MIDDLE_YYY 指位置在XXX和YYY之间
        // 从右和右下中间开始，顺时针进行编号

        //RIGHT_MIDDLE_RIGHTDOWN = 8,           => 5
        //RIGHTDOWN_MIDDLE_DOWN = 9,            => 6
        //DOWN_MIDDLE_LEFTDOWN = 10,            => 6
        //LEFTDOWN_MIDDLE_LEFT = 11,            => 5
        //LEFT_MIDDLE_LEFTUP = 12,              => 8
        //LEFTUP_MIDDLE_UP = 13,                => 7
        //UP_MIDDLE_RIGHTUP = 14,               => 7
        //RIGHTUP_MIDDLE_RIGHT = 15             => 8

        // 斜率
        private static readonly float[] ks = new float[18];

        // 斜率对应的方向
        private static readonly int[] directions =
        {
            1, 9, 0, 8, 7, 15, 6, 14, 5,
            5, 13, 4, 12, 3, 11, 2, 10, 1
        };

        // 方向对应的动画编号
        private static readonly int[] animationIndices =
        {
            0, 1, 0, 4, 3, 2, 3, 4,
            5, 6, 6, 5, 8, 7, 7, 8
        };

        private static bool isInitialized;

        public static void Initialize()
        {
            if (isInitialized)
                return;

            isInitialized = true;

            // 计算斜率，满足当 k < ks[i] 时， direction = directions[i]
            // 右半，从下逆时针向上
            var halfAngle = 45f / 4f;
            for (int i = 0; i < 8; i++)
                ks[i] = Mathf.Tan((-90f + halfAngle * (1 + i * 2)) * Mathf.Deg2Rad);
            ks[8] = float.PositiveInfinity;

            for (int i = 0; i < 8; i++)
                ks[i + 9] = Mathf.Tan((90f + halfAngle * (1 + i * 2)) * Mathf.Deg2Rad);
            ks[17] = float.PositiveInfinity;
        }

        public static int GetDirection(float3 vector,float cameraRotation)
        {
            vector = Quaternion.Euler(0, -cameraRotation, 0) * vector;
            if (math.abs(vector.x) < 0.001f)
                return vector.z > 0 ? 5 : 1;

            var k = vector.z / vector.x;
            var start = vector.x > 0 ? 0 : 9;
            for (var i = start; i < start + 9; i++)
                if (k < ks[i])
                    return directions[i];

            return 0;
        }

        public static bool GetFlip(int direction)
        {
            if (direction == 2)
                return true;
            if (direction == 3)
                return true;
            if (direction == 4)
                return true;
            if (direction == 10)
                return true;
            if (direction == 11)
                return true;
            if (direction == 12)
                return true;
            if (direction == 13)
                return true;
            return false;
        }

        public static int GetAnimationIndex(int direction)
        {
#if UNITY_EDITOR
            if (direction < 0 || direction >= animationIndices.Length)
                return direction;
#endif
            return animationIndices[direction];
        }
    }

    public class SpriteSheetAnimation8Directions
    {
        // 八个方向对应的枚举值和对应的动画编号
        // 其中左侧3个方向需要翻转，动画编号和右侧相同
        //RIGHT_DOWN = 0,                       => 0
        //DOWN = 1,                             => 1
        //LEFT_DOWN = 2,                        => 0
        //LEFT = 3,                             => 4
        //LEFT_UP = 4,                          => 3
        //UP = 5,                               => 2
        //RIGHT_UP = 6,                         => 3
        //RIGHT = 7                             => 4

        // 斜率
        private static readonly float[] ks = new float[34];
        // 斜率对应的方向
        private static readonly int[] directions =
        {
            1,1,1,0,0,0,7,7,7,7,6,6,6,6,5,5,5,
            5,5,5,4,4,4,4,3,3,3,3,2,2,2,2,1,1
        };

        // 方向对应的动画编号
        private static readonly int[] animationIndices =
        {
            0, 1, 0, 4, 3, 2, 3, 4,
            4, 1, 1, 4, 3, 2, 3, 4,
        };
        private static bool isInitialized;

        public static void Initialize()
        {
            if (isInitialized)
                return;

            isInitialized = true;

            // 计算斜率，满足当 k < ks[i] 时， direction = directions[i]
            // 右半，从下逆时针向上
            var halfAngle = 45f / 4f;
            ks[0] = float.NegativeInfinity;
            for (int i = 1; i < 16; i++)
                ks[i] = Mathf.Tan((-90f + halfAngle * i) * Mathf.Deg2Rad);
            ks[16] = float.PositiveInfinity;

            for (int i = 0; i < 16; i++)
                ks[i + 17] = Mathf.Tan((90f + halfAngle * i) * Mathf.Deg2Rad);
            ks[33] = float.PositiveInfinity;
        }

        public static int GetDirection(float3 vector,float cameraRotation = 45)
        {
            vector = Quaternion.Euler(0, -cameraRotation, 0) * vector;
            if (math.abs(vector.x) < 0.001f)
                return vector.z > 0 ? 5 : 1;

            var k = vector.z / vector.x;
            var start = vector.x > 0 ? 0 : 17;
            for (var i = start; i < start + 17; i++)
                if (k <= ks[i])
                    return directions[i];

            return 0;
        }

        public static bool GetFlip(int direction)
        {
            if (direction == 2)
                return true;
            if (direction == 3)
                return true;
            if (direction == 4)
                return true;
            if (direction == 10)
                return true;
            if (direction == 11)
                return true;
            if (direction == 12)
                return true;
            if (direction == 13)
                return true;
            return false;
        }

        public static int GetAnimationIndex(int direction)
        {
#if UNITY_EDITOR
            if (direction < 0 || direction >= animationIndices.Length)
                return direction;
#endif
            return animationIndices[direction];
        }
    }

    public class ParticleJobHelper
    {
        private static bool isInitialized;

        public static void Initialize()
        {
            if (isInitialized)
                return;

            isInitialized = true;

           SpriteSheetAnimation8Directions.Initialize();
           SpriteSheetAnimation16Directions.Initialize();
        }

        public static int GetDirection(float3 vector, bool isd16,float cameraRotation = 45)
        {
            return isd16
                ? SpriteSheetAnimation16Directions.GetDirection(vector,cameraRotation)
                : SpriteSheetAnimation8Directions.GetDirection(vector,cameraRotation);
        }

        public static bool GetFlip(int direction, bool isd16)
        {
            return isd16
                ? SpriteSheetAnimation16Directions.GetFlip(direction)
                : SpriteSheetAnimation8Directions.GetFlip(direction);
        }

        public static int GetAnimationIndex(int direction, bool isd16)
        {
            return isd16
                ? SpriteSheetAnimation16Directions.GetAnimationIndex(direction)
                : SpriteSheetAnimation8Directions.GetAnimationIndex(direction);
        }
    }
}
